package com.boil.qz.safekavass.service;

import com.boil.exception.BaseException;
import com.boil.exception.UnauthorizedException;
import com.boil.pojo.ResultVo;
import com.boil.qz.safekavass.dao.MybatisDao;
import com.boil.qz.safekavass.model.LoginUser;
import com.boil.qz.safekavass.model.ResourceEntity;
import com.boil.qz.safekavass.model.RoleEntity;
import com.boil.qz.safekavass.pojo.ResourceVo;
import com.boil.qz.safekavass.pojo.RoleVo;
import com.boil.qz.safekavass.pojo.ZTreeSimpleDataVo;
import com.boil.qz.safekavass.repository.RoleRepository;
import com.boil.qz.safekavass.web.request.param.RoleAddParam;
import com.boil.qz.safekavass.web.request.param.RoleUpdateParam;
import com.boil.util.Constants;
import com.boil.util.Page;
import com.boil.util.Utils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * Created by ChenYong on 2017-08-07.
 * <br>
 * 角色 Service。
 */
@Service
public class RoleService extends JpaRepositoryService<RoleEntity, Long> {
    /**
     * 注入 Mybatis Dao
     */
    @Autowired
    private MybatisDao mybatisDao;
    /**
     * 注入角色实体仓库
     */
    @Autowired
    private RoleRepository roleRepository;
    /**
     * 注入角色 Service
     */
    @Autowired
    private ResourceService resourceService;

    /**
     * 分页查询角色。
     *
     * @param page 分页实例
     */
    public void findInPage(Page<RoleVo> page) {
        mybatisDao.selectInPage("roleVoNs.findInPage", page);
    }

    /**
     * 根据用户 ID 查询用户已拥有的角色 <code>List</code>。
     *
     * @param userId 用户 ID
     * @return 用户已拥有的角色 <code>List</code>
     */
    public List<RoleEntity> findMyByUserId(long userId) {
        return roleRepository.findMyByUserId(userId);
    }

    /**
     * 根据用户 ID 查询用户未拥有的角色 <code>List</code>。
     *
     * @param userId 用户 ID
     * @return 用户未拥有的角色 <code>List</code>
     */
    public List<RoleEntity> findOtherByUserId(long userId) {
        return roleRepository.findOtherByUserId(userId);
    }

    /**
     * 查询资源的 zTree 数据。
     *
     * @param roleId 角色 ID
     * @return 资源的 zTree 数据
     */
    public List<ZTreeSimpleDataVo> findResourceZTree(long roleId) {
        // 查询角色
        RoleEntity roleEntity = findOne(roleId);
        // 存放角色拥有的资源 ID
        List<Long> resourceIds = new ArrayList<Long>();

        if (roleEntity != null) {
            for (ResourceEntity resourceEntity : roleEntity.getResources()) {
                resourceIds.add(resourceEntity.getId());
            }
        }

        // 查询资源
        List<ResourceVo> resourceVos = resourceService.findByExcludeIdsAndResourceTypes(null, null);
        List<ZTreeSimpleDataVo> zTreeSimpleDataVos = new ArrayList<ZTreeSimpleDataVo>();

        for (ResourceVo resourceVo : resourceVos) {
            ZTreeSimpleDataVo zTreeSimpleDataVo = new ZTreeSimpleDataVo();
            zTreeSimpleDataVo.setId(resourceVo.getId());
            zTreeSimpleDataVo.setParentId(resourceVo.getParentId());
            zTreeSimpleDataVo.setName(resourceVo.getResourceName());
            zTreeSimpleDataVo.setOpen(Constants.VALUE_TRUE);
            zTreeSimpleDataVo.setChecked(Constants.VALUE_FALSE);
            zTreeSimpleDataVo.getData().put(Constants.RESOURCE_TYPE_STR, resourceVo.getResourceType());

            // 资源类型名称
            String resourceTypeName = Constants.EMPTY_STR;

            // 菜单
            if (resourceVo.getResourceType() == Constants.VALUE_1) {
                resourceTypeName = Constants.RESOURCE_TYPE_MENU;

                // 按钮
            } else if (resourceVo.getResourceType() == Constants.VALUE_2) {
                resourceTypeName = Constants.RESOURCE_TYPE_BUTTON;

                // 数据
            } else if (resourceVo.getResourceType() == Constants.VALUE_3) {
                resourceTypeName = Constants.RESOURCE_TYPE_DATA;
            }

            if (StringUtils.isNotBlank(resourceTypeName)) {
                zTreeSimpleDataVo.setName(String.format("%s【%s】", zTreeSimpleDataVo.getName(), resourceTypeName));
            }

            // 选中根资源
            if (!resourceIds.isEmpty() && (resourceVo.getResourceType() == Constants.VALUE_0)) {
                zTreeSimpleDataVo.setChecked(Constants.VALUE_TRUE);
            }

            // 选中角色已拥有的资源
            for (Long resourceId : resourceIds) {
                if (resourceVo.getId().equals(resourceId)) {
                    zTreeSimpleDataVo.setChecked(Constants.VALUE_TRUE);
                    break;
                }
            }

            zTreeSimpleDataVos.add(zTreeSimpleDataVo);
        }

        return zTreeSimpleDataVos;
    }

    /**
     * 根据角色代码统计角色个数。
     *
     * @param roleCode 角色代码
     * @return 角色个数
     */
    public long countByRoleCode(String roleCode) {
        return roleRepository.countByRoleCode(roleCode);
    }

    /**
     * 校验角色代码。
     *
     * @param resultVo 结果 Vo
     * @param roleCode 角色代码
     */
    public void checkRoleCode(ResultVo resultVo, String roleCode) {
        // 角色代码为空
        if (StringUtils.isBlank(roleCode)) {
            resultVo.setResultCode(Constants.ROLE_CODE_EMPTY);
            resultVo.setResultMsg(Constants.ROLE_CODE_EMPTY_MSG);

            // 角色代码非空
        } else {
            // 角色代码的格式正确
            if (roleCode.matches(Constants.ROLE_RE)) {
                long count = countByRoleCode(roleCode);

                // 角色代码未存在
                if (count == Constants.VALUE_L_0) {
                    resultVo.setResultCode(Constants.SUCCESS);
                    resultVo.setResultMsg(Constants.ROLE_CODE_NOT_EXIST_MSG);

                    // 角色代码已存在
                } else {
                    resultVo.setResultCode(Constants.ROLE_CODE_EXIST);
                    resultVo.setResultMsg(Constants.ROLE_CODE_EXIST_MSG);
                }

                // 角色代码的格式不正确
            } else {
                resultVo.setResultCode(Constants.ROLE_CODE_FORMAT_ERROR);
                resultVo.setResultMsg(Constants.ROLE_CODE_FORMAT_ERROR_MSG);
            }

            resultVo.setResult(roleCode);
        }
    }

    /**
     * 保存角色实例。
     *
     * @param param 添加角色的请求参数
     */
    public void save(RoleAddParam param) {
        // 如果角色代码已存在
        if (countByRoleCode(param.getRoleCode()) > Constants.VALUE_L_0) {
            throw new BaseException(Constants.ROLE_CODE_EXIST_MSG);
        }

        // 当前时间
        Date currTime = new Date();
        // 资源编号 List
        List<Long> resourceIds = Utils.parseStr2List(param.getResourceIds(), Constants.SPLIT_1_RE, Long.class);
        // 查询资源
        List<ResourceEntity> resourceEntities = resourceService.findByIds(resourceIds);
        // 创建角色
        RoleEntity roleEntity1 = new RoleEntity();
        roleEntity1.setCreateTime(currTime);

        // 给角色赋值
        BeanUtils.copyProperties(param, roleEntity1);

        // 保存角色，并返回持久态的角色
        RoleEntity roleEntity2 = save(roleEntity1);

        // 给资源分配角色
        for (ResourceEntity resourceEntity : resourceEntities) {
            resourceEntity.getRoles().add(roleEntity2);
        }
    }

    /**
     * 更新角色实例。
     *
     * @param param 更新角色的请求参数
     */
    public void update(RoleUpdateParam param) {
        // 角色【超级管理员】禁止更新
        if (param.getId() == Constants.VALUE_L_1) {
            throw new UnauthorizedException("角色【超级管理员】禁止更新");
        }

        // 查询角色
        RoleEntity roleEntity = findOne(param.getId());

        // 解除现有的角色与资源的关联关系
        Iterator<ResourceEntity> iterator = roleEntity.getResources().iterator();
        while (iterator.hasNext()) {
            ResourceEntity resourceEntity = iterator.next();

            resourceEntity.getRoles().remove(roleEntity);
        }

        // 当前时间
        Date currTime = new Date();
        // 新资源编号 List
        List<Long> newResourceIds = Utils.parseStr2List(param.getResourceIds(), Constants.SPLIT_1_RE, Long.class);
        // 查询新资源
        List<ResourceEntity> newResourceEntities = resourceService.findByIds(newResourceIds);

        roleEntity.setCreateTime(currTime);

        // 给角色赋值
        BeanUtils.copyProperties(param, roleEntity);

        // 给资源分配角色
        for (ResourceEntity resourceEntity : newResourceEntities) {
            resourceEntity.getRoles().add(roleEntity);
        }
    }

    /**
     * 删除角色实例。
     *
     * @param id 角色 ID
     */
    public void deleteById(long id) {
        // 角色【超级管理员】禁止删除
        if (id == Constants.VALUE_L_1) {
            throw new UnauthorizedException("角色【超级管理员】禁止删除");
        }

        // 查询角色
        RoleEntity roleEntity = findOne(id);

        // 解除角色与资源的关联关系
        Iterator<ResourceEntity> resourceEntityIterator = roleEntity.getResources().iterator();
        while (resourceEntityIterator.hasNext()) {
            ResourceEntity resourceEntity = resourceEntityIterator.next();

            resourceEntity.getRoles().remove(roleEntity);
        }

        // 解除用户与角色的关联关系
        Iterator<LoginUser> loginUserIterator = roleEntity.getLoginUsers().iterator();
        while (loginUserIterator.hasNext()) {
            LoginUser loginUser = loginUserIterator.next();

            loginUser.getRoles().remove(roleEntity);
        }

        // 删除角色
        delete(roleEntity);
    }
}